#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <cstring>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
extern Log lg;

enum{
    SOCKET_ERR,
    BIND_ERR
};

uint16_t defaultport = 8080;
//std::string defaultip="0.0.0.0";
const int Size = 1024;

class UdpServer
{
public:
    UdpServer(uint16_t port,const std::string& ip):_sockfd(0),_port(port),_ip(ip)
    {}

    void Init()
    {
        //1.创建udp套接字
        _sockfd = socket(AF_INET,SOCK_DGRAM,0); //IPV4协议(PF_INIF)，UDP,阻塞
        if(_sockfd<0)
        {
            lg(Fatal,"socket create errror, sockfd: %d",_sockfd);
            exit(SOCKET_ERR);
        }
        lg(Info,"socket create success, sockfd: %d",_sockfd);
        //2.bind 套接字
        //套接字fd，结构体，结构体长度
        struct sockaddr_in local;
        bzero(&local,sizeof(local));//把结构体指定大小清0
        local.sin_addr.s_addr = inet_addr(_ip.c_str());//会把ip地址转会整数，string->uint_t32
        //local.sin_addr.s_addr = INADDR_ANY;//任意地址绑定
        //local.sin_family= htonl(AF_INET);//表明自己使用的结构体是,网络通信的协议家族
        local.sin_family= AF_INET;//表明自己使用的结构体是,网络通信的协议家族
        local.sin_port = htons(_port);//保证我的端口号是网络字节序列，因为该端口号是要给对方发送的，htons会自己把port处理成大端

        //3.bind
        int n=bind(_sockfd,(const struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            lg(Fatal,"bind error, errorno: %d,err string ：%s",errno,strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info,"bind success");
    }

    void Run()
    {
        while(_isrunning)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            //1.udp无法直接读取read，write，只能recv，flags=0，阻塞，s
            //ssize_t recvfrom(int sockfd, void* buff,size_t len,int flags,struct sockaddr* src_addr, socklen_t* addrlen);
            char inbuffer[Size];
            ssize_t n = recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,(sockaddr*)&client,&len);//从sockfd里读，读到inbuufer，大小是，是client发来的
            if(n<0)
            {
                lg(Warning,"revform errno");
                continue;
            }

            inbuffer[n]=0;

            std::string info = inbuffer;
            std::string echo_string = "server echo@ "+ info;
            std::cout<<echo_string<<std::endl;
            //收到之后，发送给客户端
            sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(sockaddr*)&client,len);

        }
    }

    ~UdpServer()
    {
        if(_sockfd<0) close(_sockfd);
    }
private:
    int _sockfd;//网络文件描述符
    uint16_t _port;//端口号
    std::string _ip;//任意地址bind 0
    bool _isrunning = true;
};